#include "in.h"

int MDBSelectBatch( struct MemTable *table , void *select_record_array , size_t select_record_array_size , size_t *select_record_array_count , ... )
{
	va_list				valist ;
	struct MemField			select_field_array[ MDB_PARSE_SELECT_FIELD_ARRAY_MAXCOUNT ] ;
	size_t				select_field_array_count ;
	void				*where_record = NULL ;
	struct MemField			where_field_array[ MDB_PARSE_WHERE_FIELD_ARRAY_MAXCOUNT ] ;
	size_t				where_field_array_count ;
	char				*select_record = NULL ;
	
	struct MemIndex			*index = NULL ;
	
	struct MemIndexDataUnit		*index_dataunit = NULL ;
	char				*record_dataunit = NULL ;
	char				*record_data = NULL ;
	struct MemIndexDataUnit		*travel_index_dataunit = NULL ;
	struct MemIndexDataUnit		*prev_index_dataunit = NULL ;
	char				*prev_record_data = NULL ;
	struct MemIndexDataUnit		*next_index_dataunit = NULL ;
	int				is_matched ;
	
	int				nret = 0 ;
	
	va_start( valist , select_record_array_count );
	
	nret = ConvertArgsToArray( valist , select_field_array , sizeof(select_field_array)/sizeof(select_field_array[0]) , & select_field_array_count ) ;
	if( nret )
	{
		TRACE_PRINTF( "ConvertArgsToArray select fields failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		TRACE_PRINTF( "ConvertArgsToArray select fields ok\n" );
	}
	
	where_record = va_arg( valist , void* ) ;
	
	nret = ConvertArgsToArray( valist , where_field_array , sizeof(where_field_array)/sizeof(where_field_array[0]) , & where_field_array_count ) ;
	if( nret )
	{
		TRACE_PRINTF( "ConvertArgsToArray where fields failed[%d]\n" , nret );
		return nret;
	}
	else
	{
		TRACE_PRINTF( "ConvertArgsToArray where fields ok\n" );
	}
	
	va_end( valist );
	
	CreateCurrentTransaction( table->db );
	
	if( where_record == NULL )
		index = NULL ;
	else
		index = QueryExecuteSchedule( table , where_field_array , where_field_array_count ) ;
	if( index )
	{
		TRACE_PRINTF( "QueryExecuteSchedule return index->index_name[%s]\n" , index->index_name );
		
		index_dataunit = QueryIndexDataUnitTreeNode( where_record , index , where_field_array , where_field_array_count ) ;
		if( index_dataunit == NULL )
		{
			TRACE_PRINTF( "QueryIndexDataUnitTreeNode return NULL , throw SQL_NOT_FOUND\n" );
			DestroyCurrentTransaction( table->db );
			return (tls_last_errno=MDB_INFO_SQL_NOT_FOUND);
		}
		else
		{
			TRACE_PRINTF( "QueryIndexDataUnitTreeNode return index_dataunit[%p]\n" , index_dataunit );
		}
		
		if( index->is_unique && where_field_array_count == index->index_field_array_count )
		{
			record_dataunit = index_dataunit->record_dataunit ;
			record_data = MDB_RECORD_DATAUNIT_TO_DATA(record_dataunit) ;
			CopyRecordFields( record_data , select_field_array , select_field_array_count , select_record_array );
			(*select_record_array_count) = 1 ;
		}
		else
		{
			travel_index_dataunit = index_dataunit ;
			while( travel_index_dataunit )
			{
				TRACE_PRINTF( "travel upping index_dataunit[%p]\n" , travel_index_dataunit );
				
				prev_index_dataunit = GetPrevIndexDataUnit( travel_index_dataunit ) ;
				if( prev_index_dataunit == NULL )
					break;
				
				prev_record_data = MDB_RECORD_DATAUNIT_TO_DATA(prev_index_dataunit->record_dataunit) ;
				is_matched = TestRecordMatched( prev_record_data , where_field_array , where_field_array_count , where_record ) ;
				if( is_matched )
					break;
				
				travel_index_dataunit = prev_index_dataunit ;
				TRACE_PRINTF( "travel upped index_dataunit[%p]\n" , travel_index_dataunit );
			}
			
			for( (*select_record_array_count) = 0 , select_record = select_record_array ; travel_index_dataunit ; (*select_record_array_count)++ )
			{
				TRACE_PRINTF( "travel downning index_dataunit[%p]\n" , travel_index_dataunit );
				
				next_index_dataunit = GetNextIndexDataUnit( travel_index_dataunit ) ;
				
				record_data = MDB_RECORD_DATAUNIT_TO_DATA(travel_index_dataunit->record_dataunit) ;
				
				if( (*select_record_array_count) < select_record_array_size )
				{
					TRACE_PRINTF( "CopyRecordDataOut\n" );
					CopyRecordFields( record_data , select_field_array , select_field_array_count , select_record );
					select_record += table->record_size ;
				}
				
				if( travel_index_dataunit > index_dataunit )
				{
					is_matched = TestRecordMatched( record_data , where_field_array , where_field_array_count , where_record ) ;
					if( is_matched )
						break;
				}
				
				travel_index_dataunit = next_index_dataunit ;
				TRACE_PRINTF( "travel downed index_dataunit[%p]\n" , travel_index_dataunit );
			}
		}
	}
	else
	{
		TRACE_PRINTF( "QueryExecuteSchedule return no index\n" );
		
		record_dataunit = QueryFirstRecordWithoutIndex( table , where_record , where_field_array , where_field_array_count ) ;
		if( record_dataunit == NULL )
		{
			TRACE_PRINTF( "QueryFirstRecordWithoutIndex return NULL , throw SQL_NOT_FOUND\n" );
			DestroyCurrentTransaction( table->db );
			return (tls_last_errno=MDB_INFO_SQL_NOT_FOUND);
		}
		
		select_record = select_record_array ;
		for( (*select_record_array_count) = 0 ; ; )
		{
			record_data = MDB_RECORD_DATAUNIT_TO_DATA(record_dataunit) ;
			if( (*select_record_array_count) < select_record_array_size )
			{
				CopyRecordFields( record_data , select_field_array , select_field_array_count , select_record );
				select_record += table->record_size ;
				(*select_record_array_count)++;
			}
			
			record_dataunit = QueryNextRecordWithoutIndex( table , record_dataunit , where_record , where_field_array , where_field_array_count ) ;
			if( record_dataunit == NULL )
				break;
		}
	}
	
	DestroyCurrentTransaction( table->db );
	
	return 0;
}

